﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PDX.ChangeTracking
{
    public class ChangeRecorder : IChangeRecorder
    {
        Stack<Change> UndoStack { get; set; }
        Stack<Change> RedoStack { get; set; }

        bool ignoreChanges = false;

        public ChangeRecorder()
        {
            UndoStack = new Stack<Change>();
            RedoStack = new Stack<Change>();
        }

        public void Record(Change change)
        {
            if (!ignoreChanges)
            {
                bool handled = false;

                if (UndoStack.Count > 0)
                {
                    var top = UndoStack.Peek();
                    if (top.Editor == change.Editor)
                    {
                        top.NewValue = change.NewValue; // merge the change
                        handled = true;
                    }
                }

                if(!handled)
                {
                    UndoStack.Push(change);
                }

                RedoStack.Clear();
            }
        }

        public void Clear()
        {
            UndoStack.Clear();
            RedoStack.Clear();
        }

        public bool CanUndo
        {
            get { return UndoStack.Count > 0; }
        }

        public bool CanRedo
        {
            get { return RedoStack.Count > 0; }
        }

        public void Undo()
        {
            if (CanUndo)
            {
                var change = UndoStack.Pop();
                try
                {
                    ignoreChanges = true;
                    UndoChange(change);
                    RedoStack.Push(change);
                }
                finally
                {
                    ignoreChanges = false;
                }
            }
        }

        public void Redo()
        {
            if (CanRedo)
            {
                var change = RedoStack.Pop();
                try
                {
                    ignoreChanges = true;
                    RedoChange(change);
                    UndoStack.Push(change);
                }
                finally
                {
                    ignoreChanges = false;
                }
            }
        }

        void UndoChange(Change change)
        {
            change.PropertyModel.Value = change.OldValue;
            change.FocusedElement.Focus();
        }

        void RedoChange(Change change)
        {
            change.PropertyModel.Value = change.NewValue;
            change.FocusedElement.Focus();
        }
    }
}
